#include <gtkmm/builder.h>
#include <gtkmm/treemodel.h>
#include <gtkmm/filechooserdialog.h>
#include <gtkmm/filechooser.h>
#include <gtkmm/dialog.h>
#include <glibmm/miscutils.h>
#include <string>
#include <gtkmm/messagedialog.h>

#include "ModuleAppmanager.h"
#include "Global.h"
#include "ServiceConnection.h"
#include "ServiceAppmanager.h"
#include "ServiceTaskmanager.h"
#include "App.h"
#include "Mainwin.h"

namespace Gnodroid {
    ModuleAppmanager::ModuleAppmanager() :
        Glib::ObjectBase("gnd_module_appmanager"),
        Module(MODULE_APPMANAGER)
    {}

    void
    ModuleAppmanager::start()
    {

        auto builder = App::getCurrentApp()->getMainwin()->getBuilder();
        builder->get_widget("tv_applist", m_pTvApplist);
        builder->get_widget("btn_app_install", m_pBtnAppInst);
        builder->get_widget("btn_app_refresh", m_pBtnAppRefresh);
        builder->get_widget("btn_app_uninstall", m_pBtnAppUninst);
        builder->get_widget("btn_app_save", m_pBtnAppSave);

        m_refTreeStore = Gtk::TreeStore::create(m_modelColumns);

        /*
        auto i1 = m_refTreeStore->append();
        (*i1)[m_modelColumns.type] = "User";
        i1 = m_refTreeStore->append();
        (*i1)[m_modelColumns.type] = "System";
*/
        __clearAppList();

        m_pTvApplist->set_model(m_refTreeStore);
        m_pTvApplist->append_column("Type", m_modelColumns.type);
        m_pTvApplist->append_column("Icon", m_modelColumns.icon);
        m_pTvApplist->append_column("Label", m_modelColumns.label);
        m_pTvApplist->append_column("Package", m_modelColumns.package_name);
        m_pTvApplist->append_column("Version", m_modelColumns.version);

        //m_pTvApplist->expand_all();

        ServiceConnection* serviceConnection =
                static_cast<ServiceConnection*> (App::getService(SERVICE_CONNECTION));
        ServiceAppmanager* serviceAppmanager =
                static_cast<ServiceAppmanager*> (App::getService(SERVICE_APPMANAGER));

        //连接信号
        serviceConnection->signal_connected().connect([this](std::string id) {

            //clear cache if different device is connected
            if (id.compare(m_strDeviceId)) {
                m_mapIconCache.clear();
            }

            m_strDeviceId = id;

            __refreshAppList();
        });

        //断开连接信号
        serviceConnection->signal_disconnected().connect([this](std::string id) {
            __clearAppList();
        });

        //应用安装信号
        m_pBtnAppInst->signal_clicked().connect([this](){
            ServiceConnection* serviceConnection = static_cast<ServiceConnection*>(App::getService(SERVICE_CONNECTION));
            ServiceTaskmanager* serviceTaskmanager = static_cast<ServiceTaskmanager*>(App::getService(SERVICE_TASKMANAGER));

            if (!serviceConnection->isConnecting()) {
                return;
            }

            Mainwin* mainwin = App::getCurrentApp()->getMainwin();

            Gtk::FileChooserDialog fileChooser(*mainwin,
                                            "选择Apk文件",
                                            Gtk::FILE_CHOOSER_ACTION_OPEN);
            fileChooser.set_current_folder(Glib::get_home_dir());

            fileChooser.add_button("取消", 1);
            fileChooser.add_button("打开", 2);

            int resp = fileChooser.run();

            if (resp != 2) {
                LOG("Not select a path");
                return;
            }
            std::string apkPath = fileChooser.get_filename();

            LOG(std::string("apk path: " + apkPath));

            serviceTaskmanager->taskInstallApp(apkPath);

            return;
        });

        //应用列表刷新按钮
        m_pBtnAppRefresh->signal_clicked().connect([this](){
            if (m_bIsRefreshing) {
                LOG_WARN("refresh btn is click when it is refreshing");
                return;
            }
            LOG("refreshing app list");
            __refreshAppList();
        });

        //应用卸载按钮
        m_pBtnAppUninst->signal_clicked().connect([this](){
            auto selectRow = m_pTvApplist->get_selection()->get_selected();
            if (!selectRow) {
                LOG_WARN("select nothing");
                return;
            }

            auto row = *selectRow;
            if (row[m_modelColumns.appType] == ModelColumns::APPTYPE_NONE
                    || row[m_modelColumns.appType] == ModelColumns::APPTYPE_SYS) {
                LOG_WARN("can not uninstall such app");
                return;
            }

            Mainwin* mainwin = App::getCurrentApp()->getMainwin();
            Gtk::MessageDialog dialog(*mainwin, std::string("uninstall app ") + std::string(row[m_modelColumns.package_name]),
                    false, Gtk::MESSAGE_QUESTION,
                    Gtk::BUTTONS_OK_CANCEL, true);
            int resp = dialog.run();
            if (resp == Gtk::RESPONSE_CANCEL) {
                LOG("stop uninstall app");
                return;
            }

            ServiceTaskmanager* service = static_cast<ServiceTaskmanager*>(App::getService(SERVICE_TASKMANAGER));
            service->taskUninstallApp(row[m_modelColumns.package_name]);
            return;
        });

        //应用保存按钮
        m_pBtnAppSave->signal_clicked().connect([this](){
            ServiceTaskmanager* serviceTaskmanager = static_cast<ServiceTaskmanager*>(App::getService(SERVICE_TASKMANAGER));
            Mainwin* mainwin = App::getCurrentApp()->getMainwin();

            auto selectRow = m_pTvApplist->get_selection()->get_selected();
            if (!selectRow) {
                LOG_WARN("select nothing");
                return;
            }

            auto row = *selectRow;
            if (row[m_modelColumns.appType] == ModelColumns::APPTYPE_NONE) {
                LOG_WARN("can not export such app");
                return;
            }

            std::string packageName = row[m_modelColumns.package_name];

            Gtk::FileChooserDialog fileChooser(*mainwin,
                                               "保存为",
                                               Gtk::FILE_CHOOSER_ACTION_SAVE);
            fileChooser.add_button("取消", 1);
            fileChooser.add_button("保存", 2);
            fileChooser.set_current_name(packageName + ".apk");
            int resp = fileChooser.run();

            if (resp != 2) {
                return;
            }

            std::string destPath = fileChooser.get_filename();

            serviceTaskmanager->taskExportApp(packageName, destPath);
            return;

        });
    }

    void
    ModuleAppmanager::stop()
    {}


    void
    ModuleAppmanager::__refreshAppList()
    {
        ServiceAppmanager* serviceAppmanager = static_cast<ServiceAppmanager*>(App::getService(SERVICE_APPMANAGER));
        m_bIsRefreshing = true;

        serviceAppmanager->getAppList([this](bool res,
                                      std::shared_ptr<std::list<AndroidApp>>/*user*/ userApps,
                                      std::shared_ptr<std::list<AndroidApp>>/*system*/ sysApps){
            m_bIsRefreshing = false;
            if (!res) {
                LOG_WARN("get app list failed");
                return;
            }

            LOG("get app list done");

            m_shrUserApps = userApps;
            m_shrSysApps = sysApps;
            __updateAppListStore();

        });
    }


    void
    ModuleAppmanager::__clearAppList()
    {
        m_refTreeStore->clear();
        auto i1 = m_refTreeStore->append();
        (*i1)[m_modelColumns.type] = "User";
        i1 = m_refTreeStore->append();
        (*i1)[m_modelColumns.type] = "System";
    }

    void
    ModuleAppmanager::__updateAppListStore()
    {
        m_refTreeStore->clear();
        auto iterUser = m_refTreeStore->append();
        (*iterUser)[m_modelColumns.type] = "User";
        (*iterUser)[m_modelColumns.appType] = ModelColumns::APPTYPE_NONE;
        (*iterUser)[m_modelColumns.icon] = Glib::RefPtr<Gdk::Pixbuf>(nullptr);


        for (AndroidApp app : *m_shrUserApps) {
            auto iterChild = m_refTreeStore->append(iterUser->children());
            (*iterChild)[m_modelColumns.label] = app.label;
            (*iterChild)[m_modelColumns.package_name] = app.package;
            (*iterChild)[m_modelColumns.version] = app.version;
            (*iterChild)[m_modelColumns.appType] = ModelColumns::APPTYPE_USER;
            (*iterChild)[m_modelColumns.icon] = Glib::RefPtr<Gdk::Pixbuf>(nullptr);
            (*iterChild)[m_modelColumns.hasSetIcon] = false;
        }

        auto iterSystem = m_refTreeStore->append();
        (*iterSystem)[m_modelColumns.type] = "System";
        (*iterSystem)[m_modelColumns.appType] = ModelColumns::APPTYPE_NONE;
        (*iterSystem)[m_modelColumns.icon] = Glib::RefPtr<Gdk::Pixbuf>(nullptr);

        for (AndroidApp app : *m_shrSysApps) {
            auto iterChild = m_refTreeStore->append(iterSystem->children());
            (*iterChild)[m_modelColumns.label] = app.label;
            (*iterChild)[m_modelColumns.package_name] = app.package;
            (*iterChild)[m_modelColumns.version] = app.version;
            (*iterChild)[m_modelColumns.appType] = ModelColumns::APPTYPE_SYS;
            (*iterChild)[m_modelColumns.icon] = Glib::RefPtr<Gdk::Pixbuf>(nullptr);
            (*iterChild)[m_modelColumns.hasSetIcon] = false;
        }

        m_pTvApplist->expand_all();

        __updateAppIcons();
        __getAppIcons();
    }

    void
    ModuleAppmanager::__getAppIcons()
    {
        auto noCacheIconApp = std::shared_ptr<std::list<AndroidApp>>(new std::list<AndroidApp>());

        for (AndroidApp app : *m_shrUserApps) {
            if (m_mapIconCache[app.package].isEmpty) {
                noCacheIconApp->push_back(app);
            }
        }

        for (AndroidApp app : *m_shrSysApps) {
            if (m_mapIconCache[app.package].isEmpty) {
                noCacheIconApp->push_back(app);
            }
        }

        ServiceAppmanager* serviceAppmanager = static_cast<ServiceAppmanager*>(App::getService(SERVICE_APPMANAGER));

        serviceAppmanager->getAppIcons(noCacheIconApp, [this](bool res, std::shared_ptr<std::list<AndroidApp>> appIcons) {

            if (!res) {
                LOG_ERROR("get app icon failed");
            }

            for (AndroidApp app : *appIcons) {
                m_mapIconCache[app.package].icon = app.icon;
                m_mapIconCache[app.package].isEmpty = false;

                //LOG("get icon of " + app.package);
            }

            __updateAppIcons();
        });

    }


    void
    ModuleAppmanager::__updateAppIcons()
    {
        //遍历store中的所用项
        m_refTreeStore->foreach_iter([this](const Gtk::TreeModel::iterator& iter)->bool {
            //LOG("update");
            auto row = *iter;
            if (row[m_modelColumns.appType] != ModelColumns::APPTYPE_NONE
                    && !row[m_modelColumns.hasSetIcon]) {
                //LOG("check");
                AppCache cache = m_mapIconCache[row[m_modelColumns.package_name]];
                if (!cache.isEmpty) {
                    row[m_modelColumns.icon] = cache.icon;
                    row[m_modelColumns.hasSetIcon] = true;
                    //LOG("set icon");
                }
            }
            return false;
        });
    }


}
